import re,os
import json
import time
from common.auth.authenticate import OpenAIKeyAuth
from rest_framework.views import APIView
from rest_framework.views import Request
from django.http import StreamingHttpResponse  # 导入StreamingHttpResponse
from langchain_huggingface import HuggingFacePipeline, ChatHuggingFace
from langchain_core.messages import (
    HumanMessage,
    SystemMessage,
)
from rest_framework.decorators import action
from common.response import result
from application.serializers.chat_serializers import ChatSerializers
from application.serializers.chat_message_serializers import  ChatMessageSerializer
import huggingface_hub

json_tree = []
menus = []
class Utils:
    
    def __init__(self, chat_model=None, application_id=None, chat_id=None, client_id=None,client_type=None):
        self.chat_model = chat_model
        self.application_id: str = application_id
        self.chat_id: str = chat_id
        self.client_id: str = client_id
        self.client_type: str = client_type
    # 指定本地 模型路径
    def chat(self,message):
            
            data = {
                'chat_id': self.chat_id, 
                'message': message,
                're_chat': False,
                'stream': False,
                'application_id': self.application_id,
                'client_id': self.client_id,
                'form_data': {},
                'image_list': [],
                'document_list': [],
                'audio_list': [],
                'client_type': 'USER',
                'node_id': None,
                'runtime_node_id': None,
                'node_data': {},
                'chat_record_id': None,
                'child_node': {}
            }
            response = ChatMessageSerializer(data = data).chat()
            if response.status_code == 200:
                return response.content
    def openai(self, msg, task):
            message = f"以{msg}为标题,{task}"
            if self.chat_model is None:
                stream = self.chat(message)
                res = json.loads(stream)
                if 'code' in res and res['code'] == 200:
                    return res['data']['content']
                time.sleep(0.3)
                return ''
            else:
                messages = [
                    SystemMessage(content="你是一个AI 助手，请以助手的身份回答我的问题"),
                    HumanMessage(content=message),
                ]
                ai_msg = self.chat_model.invoke(messages)
                content = ai_msg.content.replace("<|im_end|>", "")
                list = content.split('<|im_start|>')
                for item in list:
                    if item.startswith("assistant"):
                        content = item.replace("assistant", "").strip()
                time.sleep(0.3)
                return content
    def stream_markdown(self, data):
            try:
                msg = self.openai(data, "生成PPT大纲，输出markdown格式，主题(#),章(##),节(###),段落(-)要求包含一个主题，5-6个章，每章下面有3至4节，每节下有3至6个段落")
                list  = msg.split('\n')
                for item in list:
                    time.sleep(0.3)
                    yield "data: " + item + "\n\n"
            except Exception as e:
                yield '识别错误'
    def stream_content(self, data):
            try:
                # 心跳消息
                yield "data: keep-alive\n\n"

                # 生成封面标题
                msg = self.openai(data, "生成封面标题,要求20个字以内")
                yield "data: " + json.dumps({
                    "type": "cover",
                    "data": {
                        "title": data or "默认标题",
                        "text": msg or "默认描述"
                    }
                }) + "\n\n"

                # 生成子标题
                msg = self.openai(msg, "生成6-8个子标题，每个子标题的字数在20个字以内")
                yield "data: " + json.dumps({
                    "type": "contents",
                    "data": {
                        "items": [item.strip() for item in msg.split("\n") if item.strip()]
                    }
                }) + "\n\n"

                # 生成每个子标题的内容
                for item in msg.split("\n"):
                    if item.strip() != '':
                        yield "data: " + json.dumps({
                            "type": "transition",
                            "data": {
                                "title": item,
                                "text": self.openai(item, "扩展一下标题，要求30字以内")
                            }
                        }) + "\n\n"

                        citems = {
                            "type": "content",
                            "data": {
                                "title": item,
                                "items": []
                            }
                        }

                        msg = self.openai(item, "生成3-4条子标题，每条字数在20个字以内")
                        for citem in msg.split("\n"):
                            if citem.strip() != '':
                                text = self.openai(citem, "生成1段简介，每段要求30字以内")
                                citems["data"]["items"].append({"title": citem, "text": text})

                        yield "data: " + json.dumps(citems) + "\n\n"

                # 结束标志
                yield "data: " + json.dumps({
                    "type": "end",
                    "data": {
                        "message": "谢谢观看"
                    }
                }) + "\n\n"

            except Exception as e:
                # 错误处理
                yield "data: " + json.dumps({
                    "type": "error",
                    "data": {
                        "message": str(e)
                    }
                }) + "\n\n"
    def parse_markdown_to_json(content:str):
        sections = content.split('\n')
        current_section = {}
        for section in sections:
            match = re.match(r'^(#+)\s*(.*)', section)
            if match:
                line_texts = ""
                header_level = len(match.group(1))
                header_text = match.group(2)
                if header_text == '':
                    continue
                if current_section:
                    json_tree.append(current_section)
                if header_level == 1:
                    current_section = {
                        "type": "cover",
                        "data": {
                            "title": header_text,
                            "text": ""
                        }
                    }
                elif header_level == 2:
                    # Transition section
                    current_section = {
                        "type": "transition",
                        "data": {
                            "title": header_text,
                            "text": ""
                        }
                    }
                    menus.append(header_text)
                elif header_level == 3:
                    current_section = {
                        "type": "content",
                        "data": {
                            "title": header_text,
                            "items": []
                        }
                    }
                continue
            line = re.match(r'^-\s+(.*)$', section)
            if line:
                line_title = line.group(1)
                title_split = line_title.split('：')
                if len(title_split) > 1:
                    line_title = title_split[0]
                    line_texts = title_split[1]
                else:
                    line_texts = line_title
                if current_section and current_section["type"] == "content":
                    current_section['data']['items'].append({"title": line_title, "text": line_texts})
                elif current_section and current_section["type"] == "transition":
                    current_section['data']['text'] = line_texts
                elif current_section and current_section["type"] == "cover":
                    current_section['data']['text'] = line_texts
                continue
        if current_section:
            json_tree.append(current_section)
        if menus:
            json_tree.insert(1, {"type": "contents", "data": {"items": menus}})
        json_tree.append({"type": "end"})
        return json_tree

        #return json_tree

#将markdown解析为json
class AiPPTOutline(APIView):
    authentication_classes = [OpenAIKeyAuth]
    @action(methods=['POST'], detail=False)
    def post(self, request: Request, application_id: str):
        content = request.data.get('content')
        json_content = Utils.parse_markdown_to_json(content)
        return result.success(data=json_content)
#获取模板详情
class AiPPTTemplate(APIView):
    authentication_classes = [OpenAIKeyAuth]
    @action(methods=['POST'], detail=False)
    def post(self, request: Request, application_id: str):
        template_id = request.data.get('template_id')
        with open(f'mocks/{template_id}.json', 'r') as f:
            template = json.load(f)
            return result.success(data=template)
#ppt模板列表
class AiPPTTemplateList(APIView):
    authentication_classes = [OpenAIKeyAuth]
    @action(methods=['POST'], detail=False)
    def post(self, request: Request, application_id: str):
        category = request.data.get('category')
        id = request.data.get('id', None)
        if id is not None:
            with open(f'mocks/{id}.json', 'r') as f:
                template = json.load(f)
                return result.success(data=template)
        templates = [
            { 'name': '红色通用', 'id': 'template_1', 'cover': 'https://asset.pptist.cn/img/template_1.jpg' },
            { 'name': '蓝色通用', 'id': 'template_2', 'cover': 'https://asset.pptist.cn/img/template_2.jpg' },
            { 'name': '紫色通用', 'id': 'template_3', 'cover': 'https://asset.pptist.cn/img/template_3.jpg' },
            { 'name': '莫兰迪配色', 'id': 'template_4', 'cover': 'https://asset.pptist.cn/img/template_4.jpg' }
        ]
        return result.success(data=templates)

 
class AiPPTSlides(APIView):
    @action(methods=['GET'], detail=False)
    def get(self, request: Request, application_id: str):
        category = request.data.get('type')
        slides = []
        with open(f'mocks/slides.json', 'r') as f:
            slides = json.load(f)
        return result.success(data=slides)
 
class Chat(APIView):
    authentication_classes = [OpenAIKeyAuth]
    @action(methods=['POST'], detail=False)
    def post(self, request: Request, application_id: str):
        content = request.data.get('content')
        sections = Utils(
            application_id = application_id,
            chat_id=ChatSerializers.OpenChat(data={'user_id':request.auth.client_id, 'application_id': application_id}).open(),
            client_id=request.auth.client_id,
            client_type=request.auth.client_type
        ).stream_content(content)
        response = StreamingHttpResponse(streaming_content=sections, content_type='text/event-stream;charset=utf-8')
        return response

class LocalModel(APIView):
    authentication_classes = [OpenAIKeyAuth]
    @action(methods=['POST'], detail=False)
    def post(self, request: Request, application_id: str):
        content = request.data.get('content')

        # 登录Hugging Face Hub
        huggingface_hub.login(token="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")
        model_path = "Qwen/Qwen2.5-0.5B-Instruct"
        # 使用 HuggingFacePipeline 加载模型
        pipeline = HuggingFacePipeline.from_model_id(
            model_id=model_path,
            task="text-generation",
            device=-1,  # -1或者0 如果你有 0代表GPU
            pipeline_kwargs=dict(
                max_new_tokens=100,
                do_sample=True,
                repetition_penalty=1.03,
            ),
            model_kwargs={'trust_remote_code': True}
        )
        # 创建 ChatHuggingFace 实例
        chat_model = ChatHuggingFace(llm=pipeline)
        sections = Utils(
            chat_model
        ).stream_markdown(content)
        # return result.success(data = sections)
        response = StreamingHttpResponse(streaming_content=sections, content_type='text/event-stream;charset=utf-8')
        return response

class Markdown(APIView):
        authentication_classes = [OpenAIKeyAuth]
        @action(methods=['POST'], detail=False)
        def post(self, request: Request, application_id: str):
            content = request.data.get('content')
            user_id = 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab'
            sections = Utils(
                application_id = application_id,
                chat_id=ChatSerializers.OpenChat(data={'user_id':user_id, 'application_id': application_id}).open(),
                client_id=request.auth.client_id,
                client_type=request.auth.client_type
            ).stream_markdown(content)
            # return result.success(data = sections)
            response = StreamingHttpResponse(streaming_content=sections, content_type='text/event-stream;charset=utf-8')
            return response